iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
自我挑戰組

從0到有學習JavaScript系列 第 28

第三章 型別、值和變數-不可變的原始值和可變的物件參考

  • 分享至 

  • xImage
  •  

一、什麼是可變與不可變?
(一)原始值是不可變的(immutable)
原始值(Primitives)和物件型別(Object)有一個基本差異存在,原始值是不可變的(immutable),沒辦法改變原始值,或是改變數字是沒有意義的。但原始值中的「字串」,不可變的特性沒那麼明顯,因為字串就像是字元的陣列(arrays of characters),但仍然是不可變的。

字串是不可改變的:

let s = "hello!";
s.toUpperCase();      //回傳"HELLO"
s;                    //回傳 "hello" 原本的字串

(二)原始值為by value 做比較:
原始值 (Primitives)比較時,是藉由值(by value) 比較的,意思是兩個擁有「相同的值」才會視為相同。為什麼說字串不明顯呢? 兩個字串如果拿來被比較,在長度相同、每個索引值都一樣的情況下,才會視為相等。

原始值兩個擁有相同的值,為相等:

let a = 10;
let b = 10;
a === b;          //true 兩個變數,值相等即為相等

(三)物件是可變的(mutable),也就是物件的值可以改變

let o = {x:1};
o.x = 2;           //更改物件內的x
o.y = 3;           //新增物件內容y
o;                 //{x: 2, y: 3}

(四)物件是by reference 做比較:
物件有時被稱為(Reference types),這和原始型別不同。物件值就是參考 (references),也就是以參考(by reference)作為比較。兩個物件只有在參考(refer)相同比層的物件時,才會被視為相等。

兩個物件就算內容一樣也不相等:

let c = {value:10};
let d = {vlaue:10};
c === d;              //false

如何才能讓物件相等呢?

let a = [];
let b = a;
a === b;               //true a與b都參考相同的物件,所以他們兩個相等

(五)變數更新與傳遞

  • 原始型別為「傳值」、物件為「傳址」。
  1. 原始型別的變更: 兩個值相等,但並不會因為一個值改變,另一個值就跟著改變。b只是建立了一個新的值,並複製a的值過來用。a與b各自獨立。
let a = 10;
let b = a;
a;     //10
b;     //10

a=100;
a;     //100
b;     //10
  1. 物件的變更: 設定為相同時,兩個物件為同一個實體,會一起連動。
let c = {value:50};
let b = c;  
b;           //{value:50}
c;           //{value:50}

c.value = 100;       更改c的value值
c;           //{value:100}
b;           //{value:100} 也跟著變成100了

(六)什麼是pass by sharing?
當function參數中的物件被重新賦予值的時候,function外面的變數內容是不會被影響的。

const a = {value:200};
function changeValue(object1){
	object1 = {value:123};     //賦予值
	}

changeValue(a);
console.log(a);   //{value:200} 仍然是{value:200} 沒有變成function內賦予的值

如果不是賦予值,就會像之前的by reference狀況一樣

const c = {value:300};
function changeValue(object2){
		object2.value = 500;    //更新value值,並非重新賦予值
	}

changeValue(c);
console.log(c);        //{value:500}

(七)既然物件型別是傳址(by reference),那如何創建一個一模一樣的新物件(陣列)?
必須使用迴圈loop,用來明確拷貝該物件或陣列內的每一個元素:

let a = ["a","b","c"];            //想要拷貝的陣列
let b = [];                       //想要將a陣列內容拷貝到b
for(let i=0; i<a.length; i++){    //a[]內的每個索引,都要拷貝到b內部
	b[i] = a[i];
	}
	
let c = Array.from(b);            //ES6中,用Array.from拷貝一個陣列

console.log(c);     // ['a', 'b', 'c']

(八)如何比較兩個不同的物件或陣列?

let a = ["a","b","c"];            //想要拷貝的陣列
let b = [];
function equalArrays(a,b){
if(a===b) return true;                     //同一個陣列是相等的
if(a.length !== b.length) return false;    //大小不同的陣列是不相等的
	for(let i=0; i<a.length; i++){ 
		if(a[i] !== b[i]) return false;    //兩個陣列內的內容不相等,陣列不相等
 }
	return true;    //否則他們就是相等的
}

補充:
JavaScript 中的資料型別,分為基本型別(Primitives)和物件型別(Object)。
基本型別包含:

  • String
  • number
  • boolean
  • null
  • undefined
  • symbol

不是上述的都算物件型別:

  • 物件
  • 陣列

Reference
重新認識 JavaScript 008天
https://developer.mozilla.org/en-US/docs/Glossary/Immutable


上一篇
第三章 型別、值和變數-問題筆記 symbols part2
下一篇
第三章 型別、值和變數-問題筆記 型別轉換
系列文
從0到有學習JavaScript31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言